CPP2JSON_DECLARE_VALUE_TYPE_FORMATOR({{ class_name }})

static void *Constructor_{{ class_valid_name }} {
    return (void *)new {{ class_name }}();
}

static void Destructor_{{ class_valid_name }}(void *d) {
    delete ({{ class_name }} *)d;
}

static bool Json2Object_{{ class_valid_name }}(
    const rapidjson::Value *doc, 
    void *data, 
    std::string &err) {
    assert(data);

    {{ class_name }} *d = ({{ class_name }} *)data;
    {% for field in fields %}
    // field {{ field.field_name }}
    {
        tb::serializer::internal::TypeInfo t;
        t.typeName = "{{ field.type_name }}";
        t.isPointer = {{ field.is_pointer }};
        t.isConstArray = {{ field.is_const_array }};
        t.elementTypeName = "{{ field.element_type_name }}";
        t.constArraySize = {{ field.const_array_size }};
        const rapidjsoN::Value *val = rapidjson::GetValueByPointer(*doc, "/{{ field.field_name }}");
        if (!tb::serializer::internal::ValueWrapper<{{ field.type_name }}>::FromJson(
            val,
            &d->{{ field.field_name }},
            t,
            err)) {
            return false;
        }
    }
    {% endfor %}
    return true;
}

static bool Object2Json_{{ class_valid_name }}(
    const void *data, 
    rapidjson::value *doc, 
    rapidjson::Document::AllocatorType &allocator,
    std::string &err) {
    assert(data);

    {{ class_name }} *d = ({{ class_name }} *)data;

    rapidjson::Document doc_(rapidjson::kObjectType);
    doc_.AddMember("__$schema", "{{ class_name_dot }}", allocator);
    {% for field in fields %}
    // field {{ field.field_name }}
    {
        tb::serializer::internal::TypeInfo t;
        t.typeName = "{{ field.type_name }}";
        t.isPointer = {{ field.is_pointer }};
        t.isConstArray = {{ field.is_const_array }};
        t.elementTypeName = "{{ field.element_type_name }}";
        t.constArraySize = {{ field.const_array_size }};
        rapidjson::Value val;
        if (!tb::serializer::internal::ValueWrapper<{{ field.type_name }}>::ToJson(
            &d->{{ field.field_name }},
            &val,
            allocator, 
            t, 
            err)) {
            return false;
        }
        doc_.AddMember("{{ field.field_name }}", val, allocator);
    }
    {% endfor %}

    (*doc).Swap(doc_);

    return true;
}